package mazegame;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.HashMap;

import mazegame.Constants.Direction;


public class MazeClient {

    private int mapSize = -1;
    private int myTreasureCount = 0;
    private int clientId = -1;
	private HashMap<Integer, Integer> playerTreasureCounts = new HashMap<Integer, Integer>();
    private HashMap<Integer,MazePosition> playerPositions = new HashMap<Integer,MazePosition>();
    private HashMap<MazePosition, Integer> treasurePositions = new HashMap<MazePosition, Integer>();
    private boolean isGameJoined = false;
    private ClientStatus status = ClientStatus.CLIENT_IDLE;
    private MazeServerInterface mazeServerIntf = null;

//    private UpdateTimer timer;
//    private int updateFreq = 20;

    public ClientStatus getStatus() {
		return status;
	}

	public void setStatus(ClientStatus status) {
		this.status = status;
	}

	public enum ClientStatus
    {
        CLIENT_IDLE,
        CLIENT_GAME_STARTING,
        CLIENT_GAME_RUNNING,
    }


	public int getClientId() {
		return clientId;
	}

	public void setClientId(int clientId) {
		this.clientId = clientId;
	}

	public boolean isGameJoined() {
		return isGameJoined;
	}

	public void setGameJoined(boolean isGameJoined) {
		this.isGameJoined = isGameJoined;
	}
	
	public String initiateRemoteMazeServer(String host, int port) 
    {
		try {
			String name = "MazeServerImpl";
//			 Registry registry = LocateRegistry.getRegistry(2001);
			Registry registry = LocateRegistry.getRegistry(host,port);
			mazeServerIntf = (MazeServerInterface) registry
					.lookup(name);
			return "Server initiation successful at ip :"+host+" and port: "+port;
			
		} catch (Exception e1) {
			e1.printStackTrace();
			return "ERROR: Server initiation failed at ip :"+host+" and port: "+port;
		}
    }
	
	public String updateJoiningClient() 
    {
		try {
			this.setClientId(mazeServerIntf.joinGame());
			this.mapSize=mazeServerIntf.getMapSize();

			if (this.getClientId() != -1) {
				// Update Client Status
				this.setStatus(ClientStatus.CLIENT_GAME_STARTING);
				this.setGameJoined(true);
				return "Player join game successful. Joined player id is : "+this.getClientId();
			} else {				
				return "Player join game failed.";
			}
		} catch (RemoteException e1) {			
			e1.printStackTrace();
			return "ERROR : Player join game failed.";
		}
    }
	
	public String updateLeavingClient() 
    {
		try {
			if (mazeServerIntf.leaveGame(this.getClientId())) {
				// Update Client Status
				this.setStatus(MazeClient.ClientStatus.CLIENT_IDLE);
				this.setGameJoined(false);
				return "Player leave game successful. Leaved player id is : "+this.getClientId();
			} else {
				return "Player leave game failed.";
			}
		} catch (RemoteException e1) {
			e1.printStackTrace();
			return "ERROR : Player leave game failed.";
		}
    }
	
	
   
    public String playerMoveStatus(Direction dir) 
    {
    	GameState gameState = null;
    	String returnStatus = null;
    	
		if (status == ClientStatus.CLIENT_GAME_STARTING) {

			try {
				gameState = mazeServerIntf.move(clientId, null);
				if (gameState == null) {
					System.out
							.print("Player request move failed. Game State is null");
					return "Player request move failed. Game State is null";

				}
				if (gameState.getGameStartTickcount() <= 0) {
					status = ClientStatus.CLIENT_GAME_RUNNING;
					playerTreasureCounts = gameState.getPlayerTreasureCounts();
					playerPositions = gameState.getPlayerPositions();
					treasurePositions = gameState.getTreasurePositions();
					returnStatus = "Player moved request sent successfully";
					System.out.print("Player is runnig..");
					returnStatus = "Player is runnig..";
				}else{
					returnStatus = "Maze game starting.... "+gameState.getGameStartTickcount();
				}

			} catch (RemoteException e1) {
				e1.printStackTrace();
				return "ERROR : Player request move failed.";
			} catch (Exception e2) {
				e2.printStackTrace();
				return "ERROR : Player request move failed.";
			}

		} else if (status == ClientStatus.CLIENT_GAME_RUNNING) {

			// invoke the RMI call
			try {
				gameState = mazeServerIntf.move(clientId, dir);
				if (gameState == null) {
					System.out
							.print("Player request move failed. Game State is null");
					return "Player request move failed. Game State is null";
				} else {
					playerTreasureCounts = gameState.getPlayerTreasureCounts();
					playerPositions = gameState.getPlayerPositions();
					treasurePositions = gameState.getTreasurePositions();
					returnStatus = "Player moved request sent successfully";
				}
			} catch (RemoteException e1) {
				e1.printStackTrace();
				return "ERROR : Player request move failed.";
			} catch (Exception e2) {
				e2.printStackTrace();
				return "ERROR : Player request move failed.";
			}

		}
		return returnStatus;
    }

	public String updateMazeMap()
    {
        String mazeMap = "";
        String playerInfo = "";
        for (int i=0; i<mapSize; ++i)
        {
            for (int j=0; j<mapSize; ++j)
            {
                if (playerPositions.containsValue(new MazePosition(i, j)))
                {
                    int curId = MazeUtil.getKeyByValue(playerPositions, new MazePosition(i, j));                    		
                    int treasure = playerTreasureCounts.get(curId);
                    
                    if (curId == clientId)
                    {
                        mazeMap = mazeMap + "*" + "\b \b";
                        myTreasureCount = playerTreasureCounts.get(clientId);
                    }
                    else
                    {
                        mazeMap = mazeMap + (char)(curId + (int)'A') + "\b \b";
                        playerInfo = playerInfo + "player " + (char)(curId + (int)'A') + " owns " + treasure + "\n";
                    }
                }
                else if (treasurePositions.containsKey(new MazePosition(i, j)))
                    mazeMap = mazeMap + treasurePositions.get(new MazePosition(i, j)).toString() + "\b \b";
                else
                    mazeMap += "0\b \b";
            }
            
            mazeMap += "\n";
        }       
        
        return mazeMap + playerInfo + "my treasure is " + myTreasureCount + " and id is " + clientId + "\n";
    }
    
    
    
//    public void RequestForUpdate()
//    {
//        GameState gameState = null;
//        
//        if (status != ClientStatus.CLIENT_GAME_RUNNING && status != ClientStatus.CLIENT_GAME_STARTING)
//            return;
//        
//        // print info
//        setLogDetails("request update rmi call issued, please wait...", statusView.getText()));
//        
//        // invoke the RMI call
//        try
//        {
//            packInfo = rmiInf.RequestUpdate(clientId);
//            if (packInfo == null)
//                throw new Exception();
//        }
//        catch (RemoteException e1)
//        {
//            setLogDetails("ERROR: request update rmi call failed", statusView.getText()));
//            e1.printStackTrace();
//            return;
//        }
//        catch (Exception e2)
//        {
//            setLogDetails("ERROR: request update rmi call return null", statusView.getText()));
//            e2.printStackTrace();
//            return;
//        }
//        
//        playerTreasureCounts = gameState.playerTreasureCounts;
//        playerPositions = gameState.playerPositions;
//        treasurePositions = gameState.treasurePositions;
//        mapSize = gameState.mapSize;
//        
//        if (status == ClientStatus.CLIENT_GAME_STARTING && gameState.remainGameStartTick == 0)
//        {
//            status = ClientStatus.CLIENT_GAME_RUNNING;
//            setLogDetails(GetGamePlot() + "request update rmi call succeed", ""));
//        }
//        else if (status == ClientStatus.CLIENT_GAME_STARTING)
//        {
//            setLogDetails("game starts in " + packInfo.remainGameStartTick, ""));
//        }
//        else
//        {
//            setLogDetails(GetGamePlot() + "request update rmi call succeed", ""));
//        }
//    }
	
	
	
	
	
}
